package standalone

import (
	"github.com/DiracLee/dires-go/app/cmdline"
	"github.com/DiracLee/dires-go/app/connection"
	"github.com/DiracLee/dires-go/app/database"
	"github.com/DiracLee/dires-go/app/handler"
	"github.com/DiracLee/dires-go/app/payload"
	"strconv"
)

type HandlerFunc func(svr *Standalone, conn connection.Connection, args cmdline.CmdLine) payload.Payload

var handlers = map[string]HandlerFunc{
	cmdline.CmdSubscribe:    handleSubscribe,
	cmdline.CmdPublish:      handelPublish,
	cmdline.CmdUnsubscribe:  handleUnsubscribe,
	cmdline.CmdBGRewriteAOF: handleBGRewriteAOF,
	cmdline.CmdRewriteAOF:   handleRewriteAOF,
	cmdline.CmdFlushAll:     handleFlushAll,
	cmdline.CmdSelect:       handleSelect,
	cmdline.CmdMulti:        handleMulti,
	cmdline.CmdDiscard:      handleDiscard,
	cmdline.CmdExec:         handleExec,
	cmdline.CmdWatch:        handleWatch,
}

func handleFlushAll(svr *Standalone, conn connection.Connection, args cmdline.CmdLine) payload.Payload {
	for _, db := range svr.dbs {
		db.Flush()
	}
	if svr.aofHandler != nil {
		svr.aofHandler.AddAof(0, handler.StringsCommand(cmdline.CmdFlushAll))
	}
	return &payload.OkPayload{}
}

func handleSelect(svr *Standalone, conn connection.Connection, args cmdline.CmdLine) payload.Payload {
	if conn != nil && conn.InMultiState() {
		return payload.NewErrPayload("cannot select Storage within multi")
	}
	if len(args) != 1 {
		return payload.NewArgNumErrPayload("select")
	}
	dbIndex, err := strconv.Atoi(string(args[0]))
	if err != nil {
		return payload.NewErrPayload("ERR invalid Storage Index")
	}
	if dbIndex >= len(svr.dbs) {
		return payload.NewErrPayload("ERR Storage Index is out of range")
	}
	conn.SelectDB(dbIndex)
	return payload.NewOkPayload()
}

func selectDB(svr *Standalone, conn connection.Connection) (db database.DB, ok bool) {
	dbIndex := conn.GetDBIndex()
	if dbIndex >= len(svr.dbs) {
		return nil, false
	}
	return svr.dbs[dbIndex], true
}
